package com.gitee.wsl.logger

import kotlinx.coroutines.Job
import timber.log.Timber

/**
 * Root cause of the [Throwable].
 */
val Throwable.rootCause: Throwable?
    get() {
        var rootCause: Throwable? = this
        while (rootCause?.cause != null) {
            rootCause = rootCause.cause
        }
        return rootCause
    }

fun Throwable.logDebug() = Logger.d(this)

fun Throwable.logError() = Logger.e(this)

fun Throwable.logInfo() = Logger.i(this)

fun Throwable.logVerbose() = Logger.v(this)


inline fun println(tag:String,block:()->Unit){
    Timber.d("$tag begin....")
    block()
    Timber.d("$tag end....")
}

@Suppress("ComplexMethod")
fun display(value: Any?): String {
    return when (value) {
        null -> "null"
        is String -> "\"$value\""
        is Char -> "'$value'"
        is Long -> "${value}L"
        is Array<*> -> value.joinToString(prefix = "[", postfix = "]", transform = ::display)
        is Collection<*> -> value.joinToString(prefix = "[", postfix = "]", transform = ::display)
        is Sequence<*> -> value.joinToString(prefix = "[", postfix = "]", transform = ::display)
        is Map<*, *> -> value.entries.joinToString(
            prefix = "{",
            postfix = "}",
            transform = { (k, v) -> "${display(k)}=${display(v)}" })

        is BooleanArray -> value.joinToString(prefix = "[", postfix = "]", transform = ::display)
        is CharArray -> value.joinToString(prefix = "[", postfix = "]", transform = ::display)
        is IntArray -> value.joinToString(prefix = "[", postfix = "]", transform = ::display)
        is DoubleArray -> value.joinToString(prefix = "[", postfix = "]", transform = ::display)
        is LongArray -> value.joinToString(prefix = "[", postfix = "]", transform = ::display)
        is ShortArray -> value.joinToString(prefix = "[", postfix = "]", transform = ::display)
        is ByteArray -> value.joinToString(prefix = "[", postfix = "]", transform = ::display)
        is FloatArray -> value.joinToString(prefix = "[", postfix = "]", transform = ::display)
        is Pair<*, *> -> "(${display(value.first)}, ${display(value.second)})"
        is Triple<*, *, *> -> "(${display(value.first)}, ${display(value.second)}, ${display(value.third)})"
        else -> value.toString()
    }
}

/**
 * Print [Job] children tree.
 */
fun Job.printDebugTree(offset: Int = 0) {
    println(" ".repeat(offset) + this)

    children.forEach {
        it.printDebugTree(offset + 2)
    }

    if (offset == 0) println()
}